package com.dsl.dslallinone.controller;

import com.dsl.dslallinone.common.ApiResponse;
import com.dsl.dslallinone.dto.DslQuery;
import com.dsl.dslallinone.dto.DslQueryResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;

import com.dsl.dslallinone.mapper.DslQueryMapper;

/**
 * DSL查询演示Controller - 用于Swagger测试
 */
@RestController
@RequestMapping("/api/demo")
@Tag(name = "DSL查询演示", description = "DSL查询系统演示接口，用于Swagger功能测试")
public class DemoController {

    @Autowired(required = false)
    private DslQueryMapper dslQueryMapper;

    @PostMapping("/query")
    @Operation(
            summary = "执行DSL查询（演示版）",
            description = "执行DSL查询并返回结果，这是一个演示版本，返回模拟数据用于测试Swagger功能",
            requestBody = @RequestBody(
                    description = "DSL查询请求参数",
                    required = true,
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = DslQuery.class),
                            examples = {
                                    @ExampleObject(
                                            name = "A-当月用水Top5楼栋占比",
                                            summary = "当月用水Top5楼栋占比（pie图）",
                                            value = "{" +
                                                    "\"time\": {" +
                                                    "\"window\": {\"start\": \"2025-08-01\", \"end\": \"2025-08-31\"}," +
                                                    "\"granularity\": \"day\"" +
                                                    "}," +
                                                    "\"metrics\": [" +
                                                    "{\"fn\": \"sum\", \"expr\": \"value\", \"as\": \"sum_value\", \"unit\": \"m3\"}," +
                                                    "{\"fn\": \"pct_of_total\", \"expr\": \"sum(value)\", \"as\": \"pct_of_total\", \"unit\": \"%\"}" +
                                                    "]," +
                                                    "\"filter\": [" +
                                                    "{\"field\": \"energy_type\", \"op\": \"eq\", \"value\": \"water\"}" +
                                                    "]," +
                                                    "\"groupBy\": [\"building_id\"]," +
                                                    "\"orderBy\": [{\"field\": \"sum_value\", \"dir\": \"desc\"}]," +
                                                    "\"limit\": 5" +
                                                    "}"
                                    ),
                                    @ExampleObject(
                                            name = "B-近30日用电总量+同比环比",
                                            summary = "近30日用电总量（日粒度）+ yoy/mom（line图）",
                                            value = "{" +
                                                    "\"time\": {" +
                                                    "\"window\": {\"start\": \"2025-07-01\", \"end\": \"2025-07-30\"}," +
                                                    "\"granularity\": \"day\"" +
                                                    "}," +
                                                    "\"metrics\": [" +
                                                    "{\"fn\": \"sum\", \"expr\": \"value\", \"as\": \"sum_value\", \"unit\": \"kWh\"}," +
                                                    "{\"fn\": \"yoy\", \"expr\": \"sum(value)\", \"as\": \"yoy_rate\", \"unit\": \"%\"}," +
                                                    "{\"fn\": \"mom\", \"expr\": \"sum(value)\", \"as\": \"mom_rate\", \"unit\": \"%\"}" +
                                                    "]," +
                                                    "\"filter\": [" +
                                                    "{\"field\": \"energy_type\", \"op\": \"eq\", \"value\": \"electric\"}" +
                                                    "]," +
                                                    "\"groupBy\": [\"building_id\"]," +
                                                    "\"orderBy\": [{\"field\": \"time_bucket\", \"dir\": \"asc\"}]," +
                                                    "\"limit\": 1000" +
                                                    "}"
                                    ),
                                    @ExampleObject(
                                            name = "C-今日小时占用率实时数据",
                                            summary = "今日小时占用率（realtime，按楼层折线）",
                                            value = "{" +
                                                    "\"time\": {" +
                                                    "\"window\": {\"start\": \"2025-01-15\", \"end\": \"2025-01-15\"}," +
                                                    "\"granularity\": \"hour\"" +
                                                    "}," +
                                                    "\"metrics\": [" +
                                                    "{\"fn\": \"avg\", \"expr\": \"occupied\", \"as\": \"avg_occupied\", \"unit\": \"%\"}" +
                                                    "]," +
                                                    "\"filter\": [" +
                                                    "{\"field\": \"floor_id\", \"op\": \"in\", \"value\": [\"101\", \"102\"]}" +
                                                    "]," +
                                                    "\"groupBy\": [\"floor_id\"]," +
                                                    "\"post\": {\"fill_missing\": \"zero\"}," +
                                                    "\"source\": \"realtime\"," +
                                                    "\"limit\": 100" +
                                                    "}"
                                    )
                            }
                    )
            )
    )
    @ApiResponses(value = {
            @io.swagger.v3.oas.annotations.responses.ApiResponse(
                    responseCode = "200",
                    description = "查询成功",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = ApiResponse.class)
                    )
            ),
            @io.swagger.v3.oas.annotations.responses.ApiResponse(
                    responseCode = "400",
                    description = "参数错误",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = ApiResponse.class)
                    )
            )
    })
    public ApiResponse<DslQueryResponse> query(@Valid @RequestBody DslQuery query) {
        // 创建模拟响应数据
        DslQueryResponse response = new DslQueryResponse();
        
        // 模拟series数据
        DslQueryResponse.SeriesData series1 = new DslQueryResponse.SeriesData();
        series1.setName("building_id=101");
        
        Map<String, Object> dataPoint1 = new HashMap<>();
        dataPoint1.put("time_bucket", "2025-08-01");
        dataPoint1.put("sum_value", 123.45);
        
        Map<String, Object> dataPoint2 = new HashMap<>();
        dataPoint2.put("time_bucket", "2025-08-02");
        dataPoint2.put("sum_value", 156.78);
        
        series1.setData(Arrays.asList(dataPoint1, dataPoint2));
        response.setSeries(Arrays.asList(series1));
        
        // 模拟table数据
        DslQueryResponse.TableData table = new DslQueryResponse.TableData();
        table.setColumns(Arrays.asList("time_bucket", "building_id", "sum_value"));
        table.setRows(Arrays.asList(
                Arrays.asList("2025-08-01", "101", 123.45),
                Arrays.asList("2025-08-02", "101", 156.78)
        ));
        response.setTable(table);
        
        // 模拟meta数据
        DslQueryResponse.MetaData meta = new DslQueryResponse.MetaData();
        meta.setGranularity(query.getTime().getGranularity());
        meta.setTimeWindow(query.getTime().getWindow());
        meta.setUnit("m3");
        meta.setDataSource("demo");
        response.setMeta(meta);
        
        return ApiResponse.success(response);
    }

    @GetMapping("/health")
    @Operation(
            summary = "健康检查",
            description = "检查服务是否正常运行"
    )
    public ApiResponse<String> health() {
        return ApiResponse.success("DSL查询服务运行正常");
    }

    @GetMapping("/functions")
    @Operation(
            summary = "获取支持的函数列表",
            description = "返回DSL查询系统支持的所有函数及其说明"
    )
    public ApiResponse<List<Map<String, String>>> getFunctions() {
        List<Map<String, String>> functions = Arrays.asList(
                createFunction("sum", "求和", "sum(value)", "原单位"),
                createFunction("avg", "平均值", "avg(value)", "原单位"),
                createFunction("max", "最大值", "max(value)", "原单位"),
                createFunction("min", "最小值", "min(value)", "原单位"),
                createFunction("count", "计数", "count(*)", "个"),
                createFunction("distinct_count", "去重计数", "distinct_count(device_id)", "个"),
                createFunction("yoy", "同比", "yoy(sum(value))", "%"),
                createFunction("mom", "环比", "mom(sum(value))", "%"),
                createFunction("topN", "TopN排名", "topN(sum(value))", "-"),
                createFunction("pct_of_total", "占比", "pct_of_total(sum(value))", "%"),
                createFunction("moving_avg", "移动平均", "moving_avg(value)", "原单位"),
                createFunction("rolling_sum", "滚动求和", "rolling_sum(value)", "原单位"),
                createFunction("cumulative", "累计值", "cumulative(value)", "原单位"),
                createFunction("growth_rate", "增长率", "growth_rate(value)", "%"),
                createFunction("rank", "排名", "rank(sum(value))", "-")
        );
        
        return ApiResponse.success(functions);
    }

    private Map<String, String> createFunction(String name, String description, String example, String unit) {
        Map<String, String> function = new HashMap<>();
        function.put("name", name);
        function.put("description", description);
        function.put("example", example);
        function.put("unit", unit);
        return function;
    }

    @PostMapping("/export/csv")
    @Operation(
            summary = "导出CSV文件（演示版）",
            description = "将查询结果导出为CSV格式文件"
    )
    public ResponseEntity<byte[]> exportCsv(@Valid @RequestBody DslQuery query) {
        try {
            // 获取查询数据 - 使用演示数据
            DslQueryResponse result = createMockQueryResponse();

            // 生成CSV内容
            StringBuilder csv = new StringBuilder();
            if (result.getTable() != null && result.getTable().getColumns() != null) {
                // 添加表头
                csv.append(String.join(",", result.getTable().getColumns())).append("\n");

                // 添加数据行
                if (result.getTable().getRows() != null) {
                    for (List<Object> row : result.getTable().getRows()) {
                        for (int i = 0; i < row.size(); i++) {
                            if (i > 0) csv.append(",");
                            csv.append(row.get(i) != null ? row.get(i).toString() : "");
                        }
                        csv.append("\n");
                    }
                }
            }

            // 设置响应头
            String filename = "dsl_export_" + System.currentTimeMillis() + ".csv";
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("text/csv"));
            headers.setContentDispositionFormData("attachment", filename);

            return ResponseEntity.ok()
                    .headers(headers)
                    .body(csv.toString().getBytes(StandardCharsets.UTF_8));

        } catch (Exception e) {
            // 错误情况返回错误信息
            String errorMsg = "导出失败: " + e.getMessage();
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.TEXT_PLAIN);
            return ResponseEntity.status(500)
                    .headers(headers)
                    .body(errorMsg.getBytes(StandardCharsets.UTF_8));
        }
    }

    @PostMapping("/export/xlsx")
    @Operation(
            summary = "导出Excel文件（演示版）",
            description = "将查询结果导出为Excel格式文件"
    )
    public ResponseEntity<byte[]> exportXlsx(@Valid @RequestBody DslQuery query) {
        try {
            // 获取查询数据 - 使用演示数据
            DslQueryResponse result = createMockQueryResponse();

            // 创建Excel工作簿
            Workbook workbook = new XSSFWorkbook();
            Sheet sheet = workbook.createSheet("DSL查询结果");

            int rowNum = 0;

            // 创建表头
            if (result.getTable() != null && result.getTable().getColumns() != null) {
                Row headerRow = sheet.createRow(rowNum++);
                List<String> columns = result.getTable().getColumns();
                for (int i = 0; i < columns.size(); i++) {
                    Cell cell = headerRow.createCell(i);
                    cell.setCellValue(columns.get(i));
                }

                // 添加数据行
                if (result.getTable().getRows() != null) {
                    for (List<Object> row : result.getTable().getRows()) {
                        Row dataRow = sheet.createRow(rowNum++);
                        for (int i = 0; i < row.size(); i++) {
                            Cell cell = dataRow.createCell(i);
                            Object value = row.get(i);
                            if (value != null) {
                                if (value instanceof Number) {
                                    cell.setCellValue(((Number) value).doubleValue());
                                } else {
                                    cell.setCellValue(value.toString());
                                }
                            }
                        }
                    }
                }
            }

            // 自动调整列宽
            if (result.getTable() != null && result.getTable().getColumns() != null) {
                for (int i = 0; i < result.getTable().getColumns().size(); i++) {
                    sheet.autoSizeColumn(i);
                }
            }

            // 将工作簿写入字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            workbook.write(outputStream);
            workbook.close();

            // 设置响应头
            String filename = "dsl_export_" + System.currentTimeMillis() + ".xlsx";
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
            headers.setContentDispositionFormData("attachment", filename);

            return ResponseEntity.ok()
                    .headers(headers)
                    .body(outputStream.toByteArray());

        } catch (Exception e) {
            // 错误情况返回错误信息
            String errorMsg = "导出失败: " + e.getMessage();
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.TEXT_PLAIN);
            return ResponseEntity.status(500)
                    .headers(headers)
                    .body(errorMsg.getBytes(StandardCharsets.UTF_8));
        }
    }

    /**
     * 创建模拟查询响应数据
     */
    private DslQueryResponse createMockQueryResponse() {
        // 创建表格数据
        List<String> columns = Arrays.asList("building_id", "sum_value", "pct_of_total");
        List<List<Object>> rows = Arrays.asList(
            Arrays.asList("A01", 1250.5, 35.2),
            Arrays.asList("B02", 980.3, 27.6),
            Arrays.asList("C03", 756.8, 21.3),
            Arrays.asList("D04", 345.2, 9.7),
            Arrays.asList("E05", 218.9, 6.2)
        );

        DslQueryResponse.TableData table = new DslQueryResponse.TableData(columns, rows);

        // 创建时间序列数据
        List<DslQueryResponse.SeriesData> series = new ArrayList<>();
        for (List<Object> row : rows) {
            Map<String, Object> dataPoint = new HashMap<>();
            dataPoint.put("sum_value", row.get(1));
            dataPoint.put("pct_of_total", row.get(2));

            series.add(new DslQueryResponse.SeriesData(
                "building_id=" + row.get(0),
                Arrays.asList(dataPoint)
            ));
        }

        // 创建元数据
        DslQueryResponse.MetaData meta = new DslQueryResponse.MetaData();
        meta.setDataSource("demo");
        meta.setUnit("m3");

        return new DslQueryResponse(series, table, meta);
    }

    @PostMapping("/export/water-day-fact")
    @Operation(
            summary = "导出water_day_fact表所有数据",
            description = "直接查询water_day_fact表中的所有数据并导出为Excel文件（演示模式返回模拟数据）"
    )
    public ResponseEntity<byte[]> exportWaterDayFact() {
        try {
            List<Map<String, Object>> data;

            // 检查数据库连接是否可用
            if (dslQueryMapper == null) {
                // 演示模式：返回模拟的water_day_fact数据
                data = createMockWaterDayFactData();
            } else {
                // 真实模式：查询数据库
                String sql = "SELECT building_id, floor_id, device_id, energy_type, stat_date, value, unit " +
                            "FROM water_day_fact " +
                            "ORDER BY stat_date DESC, building_id, floor_id, device_id";

                data = dslQueryMapper.executeDynamicSql(sql);

                if (data == null || data.isEmpty()) {
                    // 如果数据库没有数据，也返回模拟数据
                    data = createMockWaterDayFactData();
                }
            }

            // 创建Excel工作簿
            Workbook workbook = new XSSFWorkbook();
            Sheet sheet = workbook.createSheet("water_day_fact数据");

            // 创建表头
            Row headerRow = sheet.createRow(0);
            String[] headers = {"building_id", "floor_id", "device_id", "energy_type", "stat_date", "value", "unit"};
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
            }

            // 添加数据行
            int rowNum = 1;
            for (Map<String, Object> row : data) {
                Row dataRow = sheet.createRow(rowNum++);

                dataRow.createCell(0).setCellValue(getString(row.get("building_id")));
                dataRow.createCell(1).setCellValue(getString(row.get("floor_id")));
                dataRow.createCell(2).setCellValue(getString(row.get("device_id")));
                dataRow.createCell(3).setCellValue(getString(row.get("energy_type")));
                dataRow.createCell(4).setCellValue(getString(row.get("stat_date")));

                Object value = row.get("value");
                if (value instanceof Number) {
                    dataRow.createCell(5).setCellValue(((Number) value).doubleValue());
                } else {
                    dataRow.createCell(5).setCellValue(getString(value));
                }

                dataRow.createCell(6).setCellValue(getString(row.get("unit")));
            }

            // 自动调整列宽
            for (int i = 0; i < headers.length; i++) {
                sheet.autoSizeColumn(i);
            }

            // 将工作簿写入字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            workbook.write(outputStream);
            workbook.close();

            // 设置响应头
            String filename = "water_day_fact_" + System.currentTimeMillis() + ".xlsx";
            HttpHeaders headers_response = new HttpHeaders();
            headers_response.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
            headers_response.setContentDispositionFormData("attachment", filename);

            return ResponseEntity.ok()
                    .headers(headers_response)
                    .body(outputStream.toByteArray());

        } catch (Exception e) {
            return createErrorResponse("导出失败: " + e.getMessage());
        }
    }

    private String getString(Object obj) {
        return obj != null ? obj.toString() : "";
    }

    private ResponseEntity<byte[]> createErrorResponse(String message) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.TEXT_PLAIN);
        return ResponseEntity.status(500)
                .headers(headers)
                .body(message.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 创建模拟的water_day_fact数据
     */
    private List<Map<String, Object>> createMockWaterDayFactData() {
        List<Map<String, Object>> data = new ArrayList<>();

        String[] buildings = {"A01", "A02", "B01", "B02", "C01"};
        String[] floors = {"F01", "F02", "F03"};
        String[] devices = {"WM001", "WM002", "WM003"};
        String[] dates = {"2025-08-01", "2025-08-02", "2025-08-03", "2025-08-04", "2025-08-05"};

        for (String building : buildings) {
            for (String floor : floors) {
                for (String device : devices) {
                    for (String date : dates) {
                        Map<String, Object> row = new HashMap<>();
                        row.put("building_id", building);
                        row.put("floor_id", floor);
                        row.put("device_id", device);
                        row.put("energy_type", "water");
                        row.put("stat_date", date);
                        row.put("value", Math.round((Math.random() * 500 + 100) * 100.0) / 100.0); // 100-600之间的随机值
                        row.put("unit", "m3");
                        data.add(row);
                    }
                }
            }
        }

        return data;
    }
}
